﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Reflection;
using VIA.Integration;
using VIA.Integration.Alarms;
using VIA.Integration.Domain;
using VIA.Integration.LeadShine;
using VIA.Presentation;
using VIA.Project.Domain.Services;
using VIA.SiMoJi.Domain.Electronics;
using VIA.SiMoJi.Domain.Inspection;
using VIA.SiMoJi.Domain.Option;
using static VT.Framework.Utils.UtilMiniDump;
using VZedGraph;
using VAssimpNet;
using VIA.Infrastructure;
using VIA.Domain.Repositories;

namespace VIA.SiMoJi.Domain.Inspection
{
    public partial class Inspector : InspectorEngine, IRefreshing
    {
        #region Field
        private readonly IMessageService _messageService;
        private const string _name = "自动撕膜设备";
        private IApplicationLog _applicationLog;
        private InspectorOption _inspectorOption;
        private bool _isStationInitialized;
        private volatile CancellationTokenSource _initCts;
        private CancellationTokenSource _refreshCts;
        private bool _isEmg;
        private ILogger _alarmLogger;
        #endregion

        #region Properties
        [Alarm(true, AlarmLevel.Warning, "已急停")]
        public bool IsEmg
        {
            get => _isEmg;
            set => NotifyAlarm(ref _isEmg, value);
        }

        public bool IsStationInitialized
        {
            get => _isStationInitialized;
            set => _isStationInitialized = value;
        }
        #endregion

        public void Refresh()
        {
            _refreshCts?.Cancel();
            _refreshCts = new CancellationTokenSource();
            Task.Factory.StartNew(async () =>
            {
                while (!_refreshCts.IsCancellationRequested)
                {
                    Feeder1.Refresh();
                    Feeder2.Refresh();
                    NGXiaLiao.Refresh();
                    Panel.Refresh();
                    Electronic.AlarmLamp.Refreshing();
                    await SafetyDoors.Refreshing();
                    ManualModeButton.Check();
                    AirSource.Refresh();
                    await Task.Delay(50);
                }
            }, TaskCreationOptions.LongRunning);
        }

        private void Inspector_AlarmStatusChanged(object? sender, AlarmEventArgs e)
        {
            try
            {
                if (!e.IsFired) return;
                if (this.StatusAlarms.Count == 0)
                {
                    Electronic.AlarmLamp.Reset();
                }
                string message = $"{e.Owner.Name}: {e.Alarm.Description}";
                if (e.Alarm.Level > AlarmLevel.Warning)
                {
                    Electronic.Default.IsAlarm = true;
                    Electronic.DI03_面板复位按钮.Value = true;
                    Electronic.AlarmLamp.YellowLight = LampState.Twinkle;
                    //LogWarning(message, LoggerCategory.Alarm);
                }
                if (e.Alarm.Level == AlarmLevel.Warning)
                {
                    Electronic.AlarmLamp.YellowLight = LampState.Twinkle;
                    LogWarningAlram(message);
                }
                else if (e.Alarm.Level == AlarmLevel.Error)
                {
                    Stop();
                    IsWhistlingOpen();
                    LogErrorAlram(message);
                }
                else if (e.Alarm.Level == AlarmLevel.Fatal)
                {
                    ForceStop();
                    IsWhistlingOpen();
                    LogErrorAlram(message);
                }
            }
            catch (Exception ex)
            {
                LogError(ex.Message, LoggerCategory.RunningInfo);
            }
        }

        #region 设备操作
        public override void Run(RunningMode runningMode)
        {
            if (runningMode == RunningMode.Online)
            {
                if (CanRun(out string msg))
                {
                    base.Run(runningMode);
                    Electronic.DO01_面板启动按钮灯.Value = true;
                    Electronic.DO02_面板停止按钮灯.Value = false;
                    Electronic.DO03_面板复位按钮灯.Value = false;
                    Electronic.AlarmLamp.Reset();
                    Electronic.AlarmLamp.GreenLight = LampState.Shine;
                    Electronic.AlarmLamp.RedLight = LampState.None;
                    Electronic.AlarmLamp.YellowLight = LampState.None;
                    _ = SafetyDoors.Enabled();
                }
                else
                {
                    LogWarning(msg);
                }
            }
        }

        public override void Stop()
        {
            try
            {
                base.Stop();
                _initCts?.Cancel();
                SignalPanel.Signal.Save();
                var axies = Flatten().Select(o => o as DmcAxis).Where(x => x != null).ToList();
                axies.ForEach(async x => await x.PauseAsync());
                Electronic.DO01_面板启动按钮灯.Value = false;
                Electronic.DO02_面板停止按钮灯.Value = true;
                Electronic.DI03_面板复位按钮.Value = false;
                Electronic.AlarmLamp.GreenLight = LampState.None;
                Electronic.AlarmLamp.RedLight = LampState.Twinkle;
                Electronic.AlarmLamp.YellowLight = LampState.None;
                SafetyDoors.Disabled();
            }
            catch (Exception ex)
            {
                LogError($"停止异常:{ex.Message}", ex, LoggerCategory.RunningInfo);
            }
        }

        public override void ForceStop()
        {
            try
            {
                Electronic.AxisEmergencyStop();
                SignalPanel.Signal.Save();
                _initCts?.Cancel();
                base.ForceStop();
                Electronic.DO01_面板启动按钮灯.Value = false;
                Electronic.DO02_面板停止按钮灯.Value = true;
                Electronic.DI03_面板复位按钮.Value = false;
                Electronic.AlarmLamp.YellowLight = LampState.None;
                Electronic.AlarmLamp.RedLight = LampState.Twinkle;
                Electronic.AlarmLamp.GreenLight = LampState.None;
                SafetyDoors.Disabled();
            }
            catch (Exception ex)
            {
                LogError($"强制停止异常:{ex.Message}", ex, LoggerCategory.RunningInfo);
            }
        }

        public override void Resume()
        {
            base.Resume();
            ClearAlarm();
            if (RunState != RunState.Running)
            {
                if (CanRun(out _))
                {
                    Electronic.AlarmLamp.GreenLight = LampState.Twinkle;
                    Electronic.AlarmLamp.RedLight = LampState.None;
                    Electronic.AlarmLamp.YellowLight = LampState.None;
                    Electronic.DO01_面板启动按钮灯.Value = false;
                    Electronic.DO02_面板停止按钮灯.Value = false;
                    Electronic.DI03_面板复位按钮.Value = true;
                }
                else
                {
                    Electronic.AlarmLamp.GreenLight = LampState.None;
                    Electronic.AlarmLamp.RedLight = LampState.Twinkle;
                    Electronic.AlarmLamp.YellowLight = LampState.None;
                    Electronic.DO01_面板启动按钮灯.Value = false;
                    Electronic.DO02_面板停止按钮灯.Value = true;
                    Electronic.DI03_面板复位按钮.Value = false;
                }
            }
        }

        public async Task InitializeStation()
        {
            try
            {
                if (CanInit(out string msg))
                {
                    IsStationInitialized = false;
                    LogInfo("全部初始化开始...", LoggerCategory.RunningInfo);
                    _ = SafetyDoors.Enabled();
                    _initCts?.Cancel();
                    _initCts = new CancellationTokenSource();
                    var token = _initCts.Token;
                    await InitializeAsync();
                    token.ThrowIfCancellationRequested();
                    Electronic.ClearAllAxisError();
                    //var axies = Flatten().Select(o => o as DmcAxis).Where(x => x != null).ToList();
                    //axies.ForEach(x => x.Reset());
                    //axies.ForEach(x => x.ServoOn(true));
                    Electronic.SetAllAxisOn();
                    var tasks = new List<Task<bool>>
                    {
                      GongLiaoStation.InitializeStation(token),
                      BanYunStation.InitializeStation(token),
                      SiMoStation.InitializeStation(token),
                    };
                    var bools = await Task.WhenAll(tasks);
                    IsStationInitialized = bools.All(x => x);
                    if (IsStationInitialized)
                    {
                        LogInfo("全部初始化完成", LoggerCategory.RunningInfo);
                    }
                    else
                    {
                        LogError("全部初始化失败，请查看各工位初始化日志！", LoggerCategory.RunningInfo);
                    }
                }
                else
                {

                    LogError($"全部初始化失败[{msg}]", LoggerCategory.RunningInfo);
                }
            }
            catch (Exception ex)
            {
                LogError($"停止初始化:{ex.Message}", ex, LoggerCategory.RunningInfo);
            }
        }

        public bool CanRun(out string msg)
        {
            msg = string.Empty;
            if (RunState == RunState.Running)
            {
                msg = $"设备已处于运行状态！";
                return false;
            }
            else if (!IsStationInitialized)
            {
                msg = $"设备未初始化无法运行！";
                return false;
            }
            else if (Electronic.IsAlarm)
            {
                msg = $"设备报警无法运行！";
                return false;
            }
            else if (!Electronic.Default.DI05_手动自动旋钮自动.Value || Electronic.Default.DI04_手动自动旋钮手动.Value)
            {
                msg = $"设备未在自动状态无法运行！";
                return false;
            }
            else if (!Electronic.Default.DI06_面板急停按钮.Value)
            {
                msg = $"设备[面板急停按钮]被按下无法运行！";
                return false;
            }
            return true;
        }

        public bool CanInit(out string msg)
        {
            msg = string.Empty;
            if (RunState == RunState.Running)
            {
                msg = $"设备运行无法初始化";
                return false;
            }
            else if (Electronic.IsAlarm)
            {
                msg = $"设备报警无法初始化";
                return false;
            }
            else if (!Electronic.Default.DI05_手动自动旋钮自动.Value || Electronic.Default.DI04_手动自动旋钮手动.Value)
            {
                msg = $"设备未在自动状态无法初始化！";
                return false;
            }
            else if (!Electronic.Default.DI06_面板急停按钮.Value)
            {
                msg = $"设备[面板急停按钮]被按下无法初始化！";
                return false;
            }
            return true;

            //bool b = RunState != RunState.Running && Electronic.Default.DI05_手动自动旋钮自动.Value && !Electronic.Default.DI04_手动自动旋钮手动.Value && !Electronic.IsAlarm;
            //return b;
        }

        public void ClearAlarm()
        {
            IsEmg = false;
            Electronic.IsAlarm = false;
            Electronic.AlarmLamp.Reset();
            Electronic.DO08_三色灯蜂鸣器1控2模组继电器.Value = false;
            ClearAlarm(this);
        }

        private void ClearAlarm(IPart part)
        {
            if (part is ISuportClearAlarm suportClearAlarm)
            {
                suportClearAlarm.ClearAlarm();
            }
            part.Automatics.ForEach(x =>
            {
                if (x is ISuportClearAlarm suportClearAlarm)
                    suportClearAlarm.ClearAlarm();
            });
            foreach (var item in part.Children)
            {
                ClearAlarm(item);
            }
        }

        void OnManualAutoStateChanged(EquipmentManualAutoState eqpManualAutoState)
        {
            if (eqpManualAutoState == EquipmentManualAutoState.Auto)
            {
                Electronic.DO04_手动自动按钮灯.On();
            }
            else
            {
                Electronic.DO04_手动自动按钮灯.Off();
            }
            ManualAutoStateChanged?.Invoke(this, new ManualAutoStateChangedEventArgs(eqpManualAutoState));
        }


        public override async Task CleanAsync()
        {
            Electronic.AlarmLamp.Reset();
            BuJinPiDai.AxisStop();
            var axies = Flatten().Select(o => o as DmcAxis).Where(x => x != null).ToList();
            axies.ForEach(async x => await x.PauseAsync());
            await Task.CompletedTask;
        }
        IOptionRepository _optionRepository;
        protected override async Task InitializeAsync(IList<IAutomatic> automatics)
        {
            try
            {
                if (_optionRepository == null)
                {
                    _optionRepository = Service.GetRequiredService<IOptionRepository>();
                    _optionRepository.OnSaved += Repository_OnSaved;
                }
                _inspectorOption = _optionRepository.Get<InspectorOption>();
                _alarmLogger = Service.GetService<ILoggerFactory>().CreateLogger("Alarm");
                string path = Path.Combine(Environment.CurrentDirectory, "AxisConfig.ini");
                Electronic.DownLoadConfigFile(path);
                Electronic.ClearCardError();
                Electronic.ClearAllAxisError();
                Electronic.SetOffsetPos(0, 0, 0);//用于轴掉电保持
                Electronic.Controller.SpeedPersent = _inspectorOption.SpeedPersent / 100;
                await ConnectAllAsync();
            }
            catch (Exception ex)
            {
                Logger.LogError(ex.Message, ex);
            }
        }

        private void Repository_OnSaved(object sender, RecipeChangedEventArgs e)
        {
            _inspectorOption = e.NewRecipe.Get<InspectorOption>();
        }

        public void InitMotionPaths(IPart part, ICurrentRecipe recipe)
        {
            var pros = part.GetType().GetProperties();
            foreach (var p in pros)
            {
                var type = typeof(IAxis);
                if (type.IsAssignableFrom(p.PropertyType))
                {
                    var atts = p.GetCustomAttributes<MotionPathAttribute>();
                    if (atts != null)
                    {
                        var instance = p.GetValue(part);
                        if (instance is DmcAxis axis)
                        {
                            DMCController.AxisNames[axis.NoId] = axis.Name;
                            var option = recipe.Get<AxisOption>(axis.Id);
                            if (option.MotionPaths == null)
                            {
                                option.MotionPaths = new List<MotionPathOption>();
                                foreach (var item in atts)
                                {
                                    option.MotionPaths.Add(new MotionPathOption() { Id = item.Name });
                                }
                            }
                            else
                            {
                                var temp = option.MotionPaths;
                                option.MotionPaths = new List<MotionPathOption>();
                                foreach (var item in atts)
                                {
                                    option.MotionPaths.Add(temp.SingleOrDefault(x => x.Id == item.Name) ?? new MotionPathOption() { Id = item.Name });
                                }
                            }
                            recipe.Set(axis.Id, option);
                            recipe.SaveAsync();
                        }
                    }
                }

            }
            foreach (var item in part.Children)
            {
                InitMotionPaths(item, recipe);
            }
        }

        private string GetVersion()
        {
            var root = Directory.GetCurrentDirectory();
            DirectoryInfo info = new DirectoryInfo(root);
            return info.GetFiles("*.exe").Select(x => x.LastWriteTime).Max().ToString("yyyy.MM.dd.HHmm");
        }

        public void CancelRefresh()
        {
            _refreshCts?.Cancel();
        }

        public void Refreshing()
        {
        }
        /// <summary>
        /// 蜂鸣器打开
        /// </summary>
        private void IsWhistlingOpen()
        {
            if (_inspectorOption?.IsCloseBuzzer == false)
            {
                if (!Electronic.AlarmLamp.IsWhistling)
                {
                    Electronic.AlarmLamp.IsWhistling = true;
                }
            }
        }
        #endregion

        #region Log
        protected void LogInfo(string message, string catalog = LoggerCategory.RunningInfo)
        {
            Logger.LogInformation(message);
            _applicationLog.LogInfo(catalog, message);
        }
        protected virtual void LogWarning(string message, string catalog = LoggerCategory.RunningInfo)
        {
            Logger.LogWarning(message);
            _applicationLog.LogWarning(catalog, message);
        }
        protected virtual void LogError(string message, Exception exception, string catalog = LoggerCategory.RunningInfo)
        {
            Logger.LogError(exception, message);
            _applicationLog.LogError(catalog, message);
        }
        protected void LogError(string message, string catalog = LoggerCategory.RunningInfo)
        {
            LogError(message, null, catalog);
        }
        protected void LogError(Exception e, string catalog = LoggerCategory.RunningInfo)
        {
            LogError(e.Message, e, catalog);
        }
        protected void LogWarningAlram(string message)
        {
            _alarmLogger.LogWarning(message);
            _applicationLog.LogWarning(LoggerCategory.Alarm, message);
        }
        protected void LogErrorAlram(string message)
        {
            _alarmLogger.LogError(message);
            _applicationLog.LogError(LoggerCategory.Alarm, message);
        }
        #endregion
    }
}
